﻿using System;
using System.Collections.Generic;
using System.Data.Entity.Validation;
using System.Globalization;
using System.Linq;
using System.Runtime.Remoting.Contexts;
using System.Text;

namespace DG.Common.EF.Logging
{
    public static class LogExtensions
        {
            public static String GetFullErrorDescription(this Exception e)
            {
                if (e == null) throw new ArgumentNullException();

                var erro = "";

                var currentError = e;
                var allErrorMsgs = new List<string>();
                var errorMsgs = new List<string>();

                while (currentError != null)
                {
                    var currentErroMsg = currentError.Message;
                    try
                    {
                        var dbEntityValidationException = e as DbEntityValidationException;
                        if (dbEntityValidationException != null)
                        {
                            currentErroMsg += Environment.NewLine
                                + "SelectedEntity Validation Exceptions:"
                                + Environment.NewLine;
                            foreach (var error in dbEntityValidationException.EntityValidationErrors)
                            {
                                foreach (var dbValidationError in error.ValidationErrors)
                                {
                                    currentErroMsg += dbValidationError.PropertyName + ":" + dbValidationError.ErrorMessage;
                                }
                            }
                        }
                    }
                    catch (Exception)
                    {
                    }

                    errorMsgs.Add(currentErroMsg);
                    allErrorMsgs.Add(currentErroMsg + Environment.NewLine + Environment.NewLine + currentError.StackTrace);
                    currentError = currentError.InnerException;
                }

                var errorMsg =
                    "Erros Resumidos" +
                    Environment.NewLine +
                    Environment.NewLine +
                    string.Join(Environment.NewLine, errorMsgs) +
                    Environment.NewLine +
                    Environment.NewLine +
                    "Erros Detalhados" +
                    Environment.NewLine +
                    Environment.NewLine +
                    string.Join(Environment.NewLine, allErrorMsgs) +
                    Environment.NewLine +
                    Environment.NewLine +
                    "StackTrace do Ambiente" +
                    Environment.NewLine +
                    Environment.NewLine +
                    Environment.StackTrace;

                erro += errorMsg;

                var msgs = new List<string>
                                   {
                                       //Application.ProductName,
                                       Environment.NewLine,
                                       Environment.NewLine,
                                       Environment.NewLine,
                                   };



                erro += string.Join(Environment.NewLine, msgs);

                return erro;

            }

            public static ILog<TLogId, TLogCampoId, TLogKeyId, TUsuarioID, TLogTipoId> RegisterException<TLogId, TLogCampoId, TLogKeyId, TUsuarioID, TLogTipoId>(this Exception e, IEFLoggable<TLogId, TLogCampoId, TLogKeyId, TUsuarioID, TLogTipoId> db)
                where TLogId : struct  , IComparable<TLogId>
                where TLogCampoId : struct  , IComparable<TLogCampoId>
                where TLogKeyId : struct  , IComparable<TLogKeyId>
                where TUsuarioID : struct  , IComparable<TUsuarioID>
                where TLogTipoId : struct  , IComparable
            {
                if (e == null) throw new ArgumentNullException();

                try
                {
                    var log = db.CreateLog();

                    log.LogTipoId = db.ErrorId;

                    var maxId = db.GetNextLogID();

                    string version;
                    string pcname;
                    string ip;
                    var user = FillInfosToLog(out version, out pcname, out ip);

                    maxId = db.GetIncrementId(maxId);

                    log.LogId = maxId;
                    log.Hora = DateTime.Now;
                    log.UsuarioId = db.UsuarioID;
                    log.UsuarioNome = db.UsuarioNome;

                    log.MachineName = pcname;
                    log.WindowsUserName = user;
                    log.OperatingSystem = version;
                    log.IP = ip;

                    log.TipoDoErro = e.GetType().FullName;


                    var logDbSet = db.Context.Set(log.GetType());
                    logDbSet.Add(log);

                    var currentError = e;
                    var allErrorMsgs = new List<string>();
                    var errorMsgs = new List<string>();

                    while (currentError != null)
                    {
                        var currentErroMsg = currentError.Message;
                        try
                        {
                            var dbEntityValidationException = e as DbEntityValidationException;
                            if (dbEntityValidationException != null)
                            {
                                currentErroMsg += Environment.NewLine
                                    + "SelectedEntity Validation Exceptions:"
                                    + Environment.NewLine;
                                foreach (var error in dbEntityValidationException.EntityValidationErrors)
                                {
                                    foreach (var dbValidationError in error.ValidationErrors)
                                    {
                                        currentErroMsg += dbValidationError.PropertyName + ":" + dbValidationError.ErrorMessage;
                                    }
                                }
                            }
                        }
                        catch (Exception)
                        {
                        }

                        errorMsgs.Add(currentErroMsg);
                        allErrorMsgs.Add(currentErroMsg + Environment.NewLine + Environment.NewLine + currentError.StackTrace);
                        currentError = currentError.InnerException;
                    }

                    var errorMsg =
                        "Erros Resumidos" +
                        Environment.NewLine +
                        Environment.NewLine +
                        string.Join(Environment.NewLine, errorMsgs) +
                        Environment.NewLine +
                        Environment.NewLine +
                        "Erros Detalhados" +
                        Environment.NewLine +
                        Environment.NewLine +
                        string.Join(Environment.NewLine, allErrorMsgs) +
                        Environment.NewLine +
                        Environment.NewLine +
                        "StackTrace do Ambiente" +
                        Environment.NewLine +
                        Environment.NewLine +
                        Environment.StackTrace;

                    log.DescricaoDoErro = errorMsg;

                    //if (askForUserMessage != null)
                    //{
                    //    log. new WPF.ErrorDialog(log).ShowDialog();
                    //}

                    var usuarioMsg = ((log.UsuarioNome != "") ? log.UsuarioNome : "Nenhum");

                    var msgs = new List<string>
                                   {
                                       //Application.ProductName,
                                       Environment.NewLine,
                                       "Usuário: " + usuarioMsg,
                                       Environment.NewLine,
                                       //"Mensagem do Usuário",
                                       //Environment.NewLine,
                                       //messagemDoUsuario,
                                       Environment.NewLine,
                                   };



                    var msg =
                        string.Join(Environment.NewLine, msgs) +
                        Environment.NewLine +
                        log.DescricaoDoErro;

                    log.DescricaoDoErro = msg;

                    db.BaseSaveChanges();

                    return log;
                }
                catch (Exception ex)
                {

                    Console.WriteLine("Não foi possível registrar o log: " + ex.Message);
                }

                return null;
            }
            public static string FillInfosToLog(out string version, out string pcname, out string ip)
            {
                #region Infos da Máquina

                var user = string.Empty;
                pcname = string.Empty;
                version = string.Empty;
                ip = string.Empty;

                try
                {
                    //var pc = new Computer();
                    pcname = Environment.MachineName;
                    user = Environment.UserName;
                    //version = pc.Info.OSFullName + " " + Environment.OSVersion.ServicePack + " " + Environment.OSVersion.Version;
                    version = Environment.OSVersion.Platform + " " + Environment.OSVersion.ServicePack + " " + Environment.OSVersion.Version;   
                }
                catch (Exception)
                {
                    Console.WriteLine("Nao foi possível obter as informações do computador para fins de Log");
                }


                try
                {
                    var ipEntry = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName());
                    var addr =
                        ipEntry.AddressList.Where(a => a.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).ToArray();

                    ip = addr[0].ToString(); //IP da Internet
                    //ip = addr[1].ToString();//IP Local                    
                }
                catch (Exception)
                {
                    Console.WriteLine("Nao foi possível obter as do ip fins de Log");
                }
                // 

                #endregion

                return user;
            }
        }
}

